iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 21
1

修改一下 userInfo template


<template>
  <div class="container">
    <b-card-group deck>
      <b-card header="帳號資訊" header-tag="header" class="m-3">
        <div role="group" class="m-3">
          <label for="account">信箱 (帳號):</label>
          <b-form-input
            id = "account"
            v-model="account"
            disabled
            trim
          ></b-form-input>
          <b-form-text id="input-live-help" v-if="!emailVerified">
            <span>您的帳號尚未認證,點擊</span>
            <span class="mail--verified"
              v-b-tooltip.hover title="發送認證信"
              @click="makeToast('success')"
            >
              連接
            </span>發送認證信
          </b-form-text>
          <b-form-text id="input-live-help" v-if="emailVerified">
            <span style="color: green;">已認證的帳號 !</span>
          </b-form-text>
        </div>

        <div role="group" class="m-3">
          <label for="password">密碼:</label>
          <b-form-input
            id = "password"
            v-model="password"
            trim
          ></b-form-input>
        </div>

        <div role="group" class="m-3">
          <label for="backupEmail">信箱 (備援):</label>
          <b-form-input
            id = "backupEmail"
            v-model="backupEmail"
            trim
          ></b-form-input>
        </div>

      </b-card>
    </b-card-group>

    <b-card-group deck>
      <b-card header="名稱相關" header-tag="header" class="m-3">
        <div role="group" class="m-3">
          <label for="">暱稱:</label>
          <b-form-input
            id="displayName"
            v-model="displayName"
            trim
          ></b-form-input>
        </div>
        <div role="group" class="m-3">
          <label for="name">英文暱稱:</label>
          <b-form-input
            id = "name"
            v-model="name"
            trim
          ></b-form-input>
        </div>
      </b-card>
    </b-card-group>

    <b-card-group deck>
      <b-card header="聯絡資訊" header-tag="header" class="m-3">
        <div role="group" class="m-3">
          <label for="phoneNumber">電話號碼:</label>
          <b-form-input
            id="phoneNumber"
            v-model="phoneNumber"
            trim
          ></b-form-input>
        </div>
        <div role="group" class="m-3">
          <label for="address">住址:</label>
          <b-form-input
            id = "address"
            v-model="address"
            trim
          ></b-form-input>
        </div>
      </b-card>
    </b-card-group>

    <b-card-group deck>
      <b-card header="簡介" header-tag="header" class="m-3">
        <div role="group" class="m-3">
          <label for="skills">專長:</label>
          <b-form-textarea
            id="skills"
            v-model="skills"
            placeholder="Enter something..."
            rows="3"
            max-rows="6"
          ></b-form-textarea>
        </div>
        <div role="group" class="m-3">
          <label for="intro">自我介紹:</label>
          <b-form-textarea
            id="intro"
            v-model="intro"
            placeholder="Enter something..."
            rows="3"
            max-rows="6"
          ></b-form-textarea>
        </div>
      </b-card>
    </b-card-group>
    <b-button @click.native="updateUserInfo" href="#" variant="primary" class="m-3">更新資料</b-button>
  </div>
</template>

...

<style lang="scss" scoped>
.mail--verified {
  color: #33f;
  cursor: pointer;

}
</style>

因為 email 認證的變數是由 firebase.auth().currentUser 裡面的 emailVerified 來負責 (應該沒記錯吧),但是這邊我實測時都會遇到一個問題,如果沒有按照正常程序進到頁面 (從登入開始進來),而是在裡面的頁面重新整理的話,每次一進到頁面就呼叫 F_showUser 時回來的使用者都是 undefined,大概要再等個 1 秒才會真的有使用者出現,我猜想可能因為 Firebase 的狀態還沒有完全更新完,背後後正在重新登入的關係,所以就不能採用一進來呼叫F_showUser 檢查 emailVerified ,而是變成先讀取資料庫,如果 emailVerified 是 false,再執行 refreshVerified,裡面有 F_showUser 的呼叫,這時確認沒問題已經可以檢查到新的使用者和認證狀態了。

所以整個程式的邏輯概念是: 一進來資訊頁時都先在 created 時讀取資料庫,若認證狀態是 false 就會執行 refreshVerified,來確認是否已經認證,若是已認證就直接更新綁定值,執行 appendCurrentValue() 並把雲端抓下來的資料丟進去,更新本地值。

data () {
  return {
    account: '',
    password: '',
    backupEmail: '',

    displayName: '',
    name: '',

    phoneNumber: '',
    address: '',

    skills: '',
    intro: '',

    photoURL: '',
    uid: '',
    emailVerified: ''
  }
}

created () {
  this.F_getManagerInfo(this.$route.params.who).then(manager => {
    if (manager.emailVerified === false) this.refreshVerified()
    else this.appendCurrentValue(manager)
  })
}

下面是所有的 methods:

methods: {
  updateUserInfo () {
    const info = this.appendCurrentValue({}, 'skip get cloud')
    this.F_updateProfile(info)
    this.F_updateManagerInfo(this.$route.params.who, info)
  },

  makeToast (variant = null) {
    this.F_sendEmailVerified()
    this.$bvToast.toast('我們已發送認證郵件至 ' + this.account + ',請點選信箱連結認證後,再重新整理確認本頁狀態。', {
      title: '提示訊息',
      variant: variant,
      solid: true
    })
  },

  appendCurrentValue (manager, order) {
    if (order === 'skip get cloud') {
      // 返回更新值
      return {
        displayName: this.displayName,
        name: this.name,
        backupEmail: this.backupEmail,
        phoneNumber: this.phoneNumber,
        address: this.address,
        // uid: this.uid,
        skills: this.skills,
        intro: this.intro
        // photoURL: this.photoURL
      }
    }

    // 取得雲端值後丟進來這裡更新綁定值
    this.account = manager.account
    this.password = manager.password
    this.backupEmail = manager.backupEmail

    this.displayName = manager.displayName
    this.name = manager.name

    this.phoneNumber = manager.phoneNumber
    this.address = manager.address

    this.skills = manager.skills
    this.intro = manager.intro
    this.emailVerified = manager.emailVerified
    // this.uid = manager.uid
    // this.photoURL = manager.photoURL
  },

  refreshVerified () {
    (async () => {
      let currentUser = null
      await this.F_showUser().then(user => {
        currentUser = user
      })
      await this.F_updateManagerInfo(this.$route.params.who, { emailVerified: currentUser.emailVerified })
      this.F_getManagerInfo(this.$route.params.who).then(manager => {
        this.appendCurrentValue(manager)
      })
    })()
  }
}

這邊等 created 結束後會看見資料被抓下來,並且顯示尚未任認證:

https://ithelp.ithome.com.tw/upload/images/20200929/20129819yDPzxjklJ0.png

透過設定好的 makeToast ,現在可以去信箱點擊收信,認證連結點下去後 emailVerified 就會變成 true,若是為 true,重新整理後就能夠看見帳號變成已認證的狀態。

https://ithelp.ithome.com.tw/upload/images/20200929/20129819zZ6kFvplHm.png

https://ithelp.ithome.com.tw/upload/images/20200929/20129819u5Ccrcr211.png

Model 大更新,建議對照 userInfo 頁來看用到什麼:

methods: {
    async F_showUser (e, msg) {
      console.log('觸發了F_showUser')
      var user = firebase.auth().currentUser
      // var name, email, photoUrl, uid, emailVerified
      if (user != null) return user
      else return null
    },

    F_signIn (account, password) {
      console.log('觸發了F_signIn')
      const self = this
      firebase.auth().signInWithEmailAndPassword(account, password).then(function () {
        console.log('登入成功')

        self.F_showUser().then(user => {
          console.log('user::', user)
          self.$router.push(`/backend/${user.uid}`)
        }).catch(error => {
          console.log(error)
        })
      }).catch(function (error) {
        // Handle Errors here.
        var errorCode = error.code
        var errorMessage = error.message
        console.error(errorCode, errorMessage)
      })
    },

    F_signUp (user) {
      return firebase.auth().createUserWithEmailAndPassword(user.account, user.password).then(function () {
      }).catch(function (error) {
        // Handle Errors here.
        var errorCode = error.code
        var errorMessage = error.message
        console.error(errorCode, errorMessage)
      })
    },

    F_signOut () {
      console.log('觸發了F_signOut')
      const self = this
      firebase.auth().signOut().then(function () {
        // Sign-out successful.
        console.log(self.$route.params)
        self.F_updateManagerInfo(self.$route.params.who, { online: false })
        self.$router.push('/')
        console.log('登出成功')
      })
    },

    F_updateArticle (data) {
      console.log('觸發了F_updateArticle')
      db.collection('posts').add(data).then(function (res) {
        console.log('新增文章成功')
      }).catch(res => {
        console.log('新增文章失敗')
      })
    },

    F_stateWatcher () {
      firebase.auth().onAuthStateChanged(function (user) {
        if (user) {
          console.log('現在使用者: ', user)
        } else {
          console.log('logout')
          //
        }
      })
    },

    F_updateProfile (userInfo) {
      console.log('觸發了F_updateProfile')
      var user = firebase.auth().currentUser
      return user.updateProfile({
        displayName: userInfo.displayName
        // photoURL: photoURL
      })
    },

    F_checkLogin () {
      console.log('觸發了F_checkLogin')
      this.F_showUser().then(res => {
        console.log(res)
        if (res === null) this.$router.push('login')
        else this.$router.push(`backend/${res.uid}`)
      })
    },

    F_getCollectionDocsSort (collection, orderBy) {
      const docs = []
      return db.collection(collection).orderBy(orderBy.where, orderBy.order).get().then(function (querySnapshot) {
        querySnapshot.forEach(function (doc) {
          const data = doc.data()
          data.id = doc.id
          docs.push(data)
        })
        return docs
      })
    },

    F_setManagerData (user) {
      db.collection('managers').doc(user.uid).set({
        account: user.account,
        password: user.password,
        displayName: user.displayName,
        name: user.name,
        backupEmail: user.backupEmail,
        phoneNumber: user.phoneNumber,
        address: user.address,
        uid: user.uid,
        emailVerified: false,
        online: user.online,
        registerTime: user.registerTime
      }).catch(function (error) {
        console.error('Error writing document: ', error)
      })
    },

    F_getManagerInfo (id) {
      var docRef = db.collection('managers').doc(id)
      return docRef.get().then(function (doc) {
        if (doc.exists) {
          return doc.data()
        } else {
          console.log('No such document!')
        }
      }).catch(function (error) {
        console.log('Error getting document:', error)
      })
    },

    F_updateManagerInfo (id, data) {
      var docRef = db.collection('managers').doc(id)
      // Set the 'capital' field of the city 'DC'
      return docRef.update(data).then(function () {
        console.log('Document successfully updated!')
      }).catch(function (error) {
        // The document probably doesn't exist.
        console.error('Error updating document: ', error)
      })
    },

    F_sendEmailVerified () {
      var user = firebase.auth().currentUser
      user.sendEmailVerification().then(function () {
        // Email sent.
      }).catch(function (error) {
        console.log(error)
      })
    }
  }

這樣註冊流程大概算 OK 了,細部有什麼問題就再說吧,更改密碼和帳號那些太麻煩了,後面通通都給他 disable 好了哈哈。

現在已經做好了寫文章、比較完整的註冊、註冊後的資料填寫、點擊進去文章,那麼下一章我們就來做編輯現有文章吧 ! Firestore 用到現在,不用我說編輯文章應該比較有個底了,大致上的邏輯我們蒐集所有的已 PO 文章,接著藉由他的特有 ID 從資料庫抓下來,更改完後重新上傳,這樣前台就會看到文章已經更新啦!

最後想說有點抱歉的是,畢竟這不是事先準備好的專案,這是很突然的要參加鐵人賽後才開始寫的內容阿,所以請原諒我很多東西變來變去,有點雜亂無章哈哈,有機會的話,明年再考慮看看能不能事先準備再來參加。


沒事也可以逛逛我們其他團隊成員的文章啦 ~~
eien_zheng: 前端小嘍嘍的Golang學習旅程_The journey of learning Golang 系列
PollyPO技術: 前端設計轉前端工程師-JS踩坑雜記 30 天 系列
阿電: 忍住不打牌位,只要30天VueJS帶你上A牌 系列
喬依司: 實作經典 JavaScript 30 系列


上一篇
Day 20: 完善註冊流程 01 - 前台註冊優化
下一篇
Day 22: 編輯現有文章,利用 $attrs 傳遞資料
系列文
Vue CLI + Firebase 雲端資料庫 30天打造簡易部落格及後臺管理30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言